package development.game;

import iplayparticle.view.iplayparticleResources;

import java.util.Vector;

import state.GameAlert;
import state.GameConstants;
import state.GameForm;
import state.GameGlobal;
import state.GameImage;
import state.Graphics;
import state.Key;
import state.TimerListener;
import state.font.FontManager;
import state.font.ImageText;
import state.socket.DataPackage;
import state.socket.DataReceiveListener;
import state.socket.MapDataPackage;
import state.util.GameColor;
import state.util.GameStringUtils;
import state.util.Hashtable;
import state.util.ImageUtil;
import state.util.array.StringArray;
import development.Constants;
import development.DrawUtils;
import development.Global;
import development.bean.Game;
import development.bean.User;
import development.bean.XiToGroupCardValue;
import development.bean.XiToPlayerInfo;
import development.group.FrmGroupListTableFreeUserChat;
import development.group.FrmGroupTableFreeUserFriend;
import development.socket.SocketClientUtil;

public class FrmXiTo extends GameForm implements DataReceiveListener, TimerListener {
  private final int OPEN_CARD_REQUEST = 6002;
  private final int CALL_ACTION_REQUEST = 6003;
  
  private final int USER_ORDER_RESPONSE = 7001;
  private final int CARD_DELIVER_RESPONSE = 7002;
  private final int OPEN_CARD_RESULT_RESPONSE = 7004; //Gửi về kết quả mở bài của tất cả các user 
  private final int START_CALL_ROUND_RESPONSE = 7005; // Chỉ định người chơi bắt đầu tố
  private final int NEXT_TURN_RESPONSE = 7006; // Chỉ định người chơi theo tố
  private final int USER_ACTION_NOTIFY_RESPONSE = 7007; // Báo hành động của 1 user cho các user khác
  private final int SEND_RESULT_RESPONSE = 7008;
  private final int INIT_TABLE_ERROR_RESPONSE = 7009; // Báo cho client biết là khởi tạo bàn lỗi
  private final int UPDATE_GAME_INFO_RESPONSE = 7010; // Cập nhật lại thông tin game cho client
  private final int NOT_ENOUGH_MONEY_REPONSE = 7011; // Khi user không đủ tiền để tố 
  private final int FIRST_CALL_ALREADY_DONE = 7012; // Báo cho client biết là lần gọi đầu tiên đã xong
  private final int TIME_OUT_RESPONSE = 7013; // Báo cho client thời gian time out
  private final int USER_LEFT_TABLE_RESPONSE = 7014; // Báo là có user thoát khỏi bàn chơi
  private static final int INIT_FOR_VIEW_USER_HEADER = 7015;
  private static final int USER_VIEW_JOIN_HEADER = 7016;
  
  // Các action của người chơi trong lượt call
  private final int QUART_CALL_ACTION_TYPE = 5002; // Tố thêm 1/4
  private final int HAFT_CALL_ACTION_TYPE = 5003; // Tố thêm 1 nửa
  private final int FULL_CALL_ACTION_TYPE = 5004; // Tố thêm tất cả
  private final int DOUBLE_CALL_ACTION_TYPE = 5005; // Tố thêm gấp đôi
  private final int FOLLOW_CALL_ACTION_TYPE = 5006; // Theo 
  private final int RETREAT_CALL_ACTION_TYPE = 5007; // Úp bỏ
  
  // Các state của ván chơi
  private final int WAIT_TO_OPEN_CARD_STATE = 9001;
  private final int WAIT_TO_CALL_STATE = 9002;
  private final int END_MATCH_STATE = 9003;
  
  private final int CARD_DISTANCE = 20;
  
  private final int BUTTON_HOZ_DIS = 15;
  private final int SCROLL_DY = 20;
  private final int BUTTON_DY = 45;
  private final int BUTTON_BG_Y = 100;
  
  private final int[][][] USER_CARDS_LOCATION_240x320 = new int[][][] 
   {
     {{70, 255}, {180, -30}},
     {{70, 255}, {270, 86}, {180, -30}},
     {{70, 255}, {270, 86}, {180, -30}, {-30, 86}},
     {{50, 255}, {270, 100}, {270, -50}, {-30, 0}, {-30, 152}}
   };
  
  private final int[][][] USER_CARDS_LOCATION_320x240 = new int[][][] 
   {
     {{110, 180}, {230, -30}},
     {{110, 180}, {330, 30}, {230, -30}},
     {{110, 180}, {330, 30}, {230, -30}, {-30, 50}},
     {{5, 180}, {165, 180}, {330, 30}, {270, -30}, {110, -30}}
   };
  
  private final int[][][] ADD_MONEY_LOCATION_240x320 = new int[][][]
   {
     {{105, 195}, {105, 65}},
     {{105, 195}, {170, 150}, {105, 65}},
     {{105, 195}, {170, 150}, {105, 65}, {40, 135}},
     {{105, 195}, {170, 190}, {170, 30}, {40, 30}, {40, 190}}
   };
   
   private final int[][][] ADD_MONEY_LOCATION_320x240 = new int[][][]
   {
     {{160, 148}, {150, 40}},
     {{160, 148}, {225, 105}, {150, 40}},
     {{160, 148}, {225, 105}, {150, 40}, {40, 105}},
     {{30, 150}, {190, 150}, {230, 110}, {190, 40}, {30, 40}}
   };

  private final boolean[][] IS_ROTATE_CARD_240x320 = new boolean[][]
   {
     {false, false},
     {false, true, false},
     {false, true, false, true},
     {false, true, true, true, true}
   };
  
  private final boolean[][] IS_ROTATE_CARD_320x240 = new boolean[][]
   {
     {false, false},
     {false, true, false},
     {false, true, false, true},
     {false, false, true, false, false}
   };
  
  private final int[][][] CARD_VALUE_LOCATION_240x320 = new int[][][]
   {
    {{70, 237}, {170, 45}},
    {{70, 237}, {230, 106}, {170, 45}},
    {{70, 237}, {230, 106}, {170, 45}, {10, 160}},
    {{70, 237}, {230, 132}, {200, 55}, {10, 100}, {10, 172}}
   };
  
  private final int[][][] CARD_VALUE_LOCATION_320x240 = new int[][][]
   {
    {{130, 165}, {210, 0}},
    {{130, 165}, {310, 80}, {210, 0}},
    {{130, 165}, {310, 80}, {210, 0}, {10, 86}},
    {{35, 165}, {175, 165}, {310, 70}, {220, 0}, {80, 0}}
   };
  
  private final int[][][] COUNT_TIME_OUT_LOCATION_240x320 = new int[][][]
   {
    {{120, 230}, {120, 90}},
    {{120, 230}, {180, 150}, {120, 90}},
    {{120, 230}, {180, 150}, {120, 90}, {70, 120}},
    {{120, 230}, {180, 150}, {190, 90}, {70, 90}, {70, 160}}
   };
  
  private final int[][][] COUNT_TIME_OUT_LOCATION_320x240 = new int[][][]
   {
    {{160, 155}, {165, 50}},
    {{160, 155}, {250, 120}, {165, 50}},
    {{160, 155}, {250, 120}, {165, 60}, {65, 120}},
    {{45, 155}, {205, 155}, {250, 120}, {260, 50}, {100, 50}}
   };
  
  private final boolean[][] IS_CARD_RIGHT_TO_LEFT_240x320 = new boolean[][]
   {
     {false, true},
     {false, true, true},
     {false, true, true, false},
     {false, true, true, false, false}
   };
  
  private final boolean[][] IS_CARD_RIGHT_TO_LEFT_320x240 = new boolean[][]
  {
    {false, true},
    {false, true, true},
    {false, true, true, false},
    {false, false, true, true, true}
  };
  
  private final boolean[][] IS_INFO_RIGHT_TO_LEFT_240x320 = new boolean[][]
   {
    {false, true},
    {false, true, true},
    {false, true, true, false},
    {false, true, true, false, false}
   };
  
  private final boolean[][] IS_INFO_RIGHT_TO_LEFT_320x240 = new boolean[][]
  {
   {false, true},
   {false, true, true},
   {false, true, true, false},
   {false, false, true, false, false}
  };
  
//  private final int[][][] CHAT_LOCATION_240x320 = new int[][][] 
//  {
//    {{20, 240}, {180, 0}},
//    {{20, 240}, {200, 210}, {180, 0}},
//    {{20, 240}, {200, 210}, {180, 0}, {0, 40}},
//    {{110, 165}, {143, 140}, {143, 30}, {54, 25}, {54, 140}}
//  };
// 
// private final int[][][] CHAT_LOCATION_320x240 = new int[][][] 
//  {
//    {{60, 160}, {250, 0}},
//    {{60, 160}, {280, 130}, {250, 0}},
//    {{80, 160}, {280, 160}, {230, 0}, {0, 10}},
//    {{78, 137}, {200, 125}, {215, 67}, {162, 5}, {78, 5}}
//  };
  
  private final int[][][] USER_INFO_LOCATION_240x320 = new int[][][] 
   {
     {{20, 240}, {220, 0}},
     {{20, 240}, {240, 210}, {220, 0}},
     {{20, 240}, {240, 210}, {220, 0}, {0, 40}},
     {{110, 165}, {183, 140}, {183, 30}, {54, 25}, {54, 140}}
   };
  
  private final int[][][] USER_INFO_LOCATION_320x240 = new int[][][] 
   {
     {{60, 160}, {290, 0}},
     {{60, 160}, {320, 130}, {290, 0}},
     {{80, 160}, {320, 160}, {270, 0}, {0, 10}},
     {{78, 137}, {200, 125}, {255, 67}, {162, 5}, {78, 5}}
   };
  
  private int[][] userCardLocation;
  private int[][] userInfoLocation;
  private int[][] cardValueLocation; 
  private int[][] countTimeOutLocation;
  private boolean[] isCardRightToLeft;
  private boolean[] isInfoRightToLeft;
  private boolean[] isRotateCard;
  private int[][] addMoneyLocation;
  
  private final String[] CARD_NAME = {" 2", " 3", " 4", " 5", " 6", " 7", " 8", " 9", " 10", " J", " Q", " K", " A"};
  private final String[] CARD_TYPE = {" Bích", " Nhép", " Rô", " Cơ"};
  
  private Vector players;
  private XiToPlayerInfo currentPlayer;
  
  private GameImage imgBaiUp;
  private GameImage rotatedImgBaiUp;
  private GameImage[] cardImges;
  private GameImage chuyenLuotImg;
  private GameImage tableImage;

  private GameImage arrowImage;
  private GameImage backButtonImage;
  private GameImage nextButtonImage;
  private GameImage sliderButtonImage;
  private GameImage bgButtonImage;
  private GameImage followButtonImage;
  private GameImage toButtonImage;
  private GameImage cancelButtonImage;
  private GameImage sliderImage;
  
  private int drawCardValueCountTime;
  private boolean hasCardValue;
  private ImageText text8;
  private ImageText text11;
  
  private int turnNumber;
  private int matchState;
  private int allBid;
  private int currentChooseCard;
  private XiToPlayerInfo currentTurn;
  private int count;
  private String message;
  private int callMenuSelectedIndex;
  private int callMoneySelectedIndex;
  private int lastCalledMoney;
  private boolean isTheFirstPlayerCall;
  private Hashtable rotatedImageCache;
  private XiToGroupCardValue xiToGroupCardValue;
  private String[] cardOrder;
  private int timeOutTime;
  private int followActionMoney;
  
  private StringArray resultName;
  private int[] resultMoney;
  private boolean isViewUser;
  
  private static GameForm singleton;
  
  public static GameForm instance() {
    if (singleton == null) {
      singleton = new FrmXiTo();
    }
    return singleton;
  }
  
  public void init(Hashtable parameters) {
    isViewUser = false;
    backButtonImage = ImageUtil.getImage(Constants.CARD_IMAGE_CATEGORY, "button_back.png");
    nextButtonImage = ImageUtil.rotate(backButtonImage, 180);
    sliderButtonImage = ImageUtil.getImage(Constants.XI_TO_IMAGE_CATEGORY, "button_slider.png");
    bgButtonImage = new GameImage(iplayparticleResources.image_button, null, null);
    followButtonImage = ImageUtil.getImage(Constants.XI_TO_IMAGE_CATEGORY, "icon_theo.png");
    toButtonImage = ImageUtil.getImage(Constants.XI_TO_IMAGE_CATEGORY, "icon_to.png");
    cancelButtonImage = ImageUtil.getImage(Constants.XI_TO_IMAGE_CATEGORY, "icon_upbo.png");
    sliderImage = ImageUtil.getImage(Constants.XI_TO_IMAGE_CATEGORY, "slider.png");
    chuyenLuotImg = ImageUtil.getImage(Constants.NEW_IMAGE_CATEGORY, "Nen_So.png");
    imgBaiUp = ImageUtil.getImage(Constants.CARD_IMAGE_CATEGORY, "Bai_MSau.png");
    rotatedImgBaiUp = ImageUtil.rotate(imgBaiUp, 90);
    arrowImage = ImageUtil.rotate(backButtonImage, 90);
    tableImage = ImageUtil.getImage(Constants.CARD_IMAGE_CATEGORY, "bg_Danh-bai.png");
    
    // Khởi tạo các ảnh quân bài
    cardOrder = new String[] {"Bich", "Nhep", "Ro", "Co"};
    cardImges = new GameImage[52];
    
    xiToGroupCardValue = new XiToGroupCardValue();
    text8 = FontManager.getFont(FontManager.FONT_SIZE_8);
    text11 = FontManager.getFont(FontManager.FONT_SIZE_11);
    hasCardValue = false;
    drawCardValueCountTime = 0;
    matchState = WAIT_TO_OPEN_CARD_STATE;
    currentChooseCard = 0;
    count = -1;
    message = null;
    resultName = null;
    resultMoney = null;
    lastCalledMoney = -1;
    
    callMenuSelectedIndex = 0;
    callMoneySelectedIndex = 1;
    isTheFirstPlayerCall = true;
    timeOutTime = 300;
    followActionMoney = 0;
    
    setTimerListener(this);
    rotatedImageCache = new Hashtable();
    DrawUtils.setBottomBar(_manager, "", "", "Thoát");
    _manager.enableTouchPad();
  }
  
  public void draw(Graphics g) {
    DrawUtils.drawBackground(g);
    g.drawImage(tableImage, Constants.SCREEN_WIDTH / 2, (Constants.SCREEN_HEIGHT - 25) / 2, Constants.CENTER_ANCHOR);
    
    for (int i = 0; i < players.size(); i++) {
      XiToPlayerInfo player = (XiToPlayerInfo) players.elementAt(i);
      if (!player.isLeftTable()) {
        // Draw user info
        drawUserInfo(g, player, userInfoLocation[i][0], userInfoLocation[i][1], isInfoRightToLeft[i]);
        
        // Draw cards of users
        drawUserCard(g, player, userCardLocation[i][0], userCardLocation[i][1], isRotateCard[i], isCardRightToLeft[i]);
        
        // Draw card value
        if (player.getUser().getName().equals(Global.currentUser.getName()) && drawCardValueCountTime > 0) {
          drawGroupCardvalue(g, player, cardValueLocation[i][0], cardValueLocation[i][1], isCardRightToLeft[i]);
        }
      }
    }
    
    drawMenu(g);
    drawTimeOut(g);
    drawBid(g);
    
    // Nếu đang là lượt tố của người chơi hiện tại
    if ((matchState == WAIT_TO_CALL_STATE) && (currentTurn == currentPlayer) && !isViewUser) {
      drawSelectCallBoard(g);
    }
    
    drawMessage(g);
    Global.drawChat(g);
    if (resultName != null) {
      drawFinalResult(g);
    }
  }
  
  private void drawFinalResult(Graphics g) {
    for (int i = 0; i < resultName.len(); i++) {
      int winPlayerIndex = getUserIndex(getPlayerByName(resultName.array[i]));
      String winString = String.valueOf(resultMoney[i]);
      g.setColor(GameColor.RED2_CODE);
      if (resultMoney[i] > 0) {
        g.setColor(0x3CA446);
        winString = "+" + resultMoney[i];
      }
      int length = text11.stringWidth(winString);
      g.fillRect(addMoneyLocation[winPlayerIndex][0], addMoneyLocation[winPlayerIndex][1], length + 4, 20);
      text11.setBold(true);
      text11.drawString2(g, winString, GameColor.WHITE_CODE, addMoneyLocation[winPlayerIndex][0], addMoneyLocation[winPlayerIndex][1] - 5, Constants.TOP_LEFT_ANCHOR);
      text11.setBold(false);
    }
  }
  
  private void drawMenu(Graphics g) {
    if (currentPlayer != null && (matchState == WAIT_TO_OPEN_CARD_STATE) && (currentPlayer.getOpenedCards().size() < turnNumber) && !isViewUser) {
      DrawUtils.getBottomBar(_manager).setCenterLabel("Mở bài");
    } else {
      if (resultName != null) {
        DrawUtils.getBottomBar(_manager).setCenterLabel("Chơi tiếp");
      } else {
        DrawUtils.getBottomBar(_manager).setCenterLabel("");
      }
    }
  }
  
  private void drawBid(Graphics g) {
    text11.setBold(true);
    text11.drawString2(g, "Tiền Cược", GameColor.RED2_CODE, Constants.SCREEN_WIDTH / 2, Constants.SCREEN_HEIGHT / 2 - 20, Constants.CENTER_ANCHOR);
    text11.drawString2(g, String.valueOf(allBid), GameColor.RED2_CODE, Constants.SCREEN_WIDTH / 2, Constants.SCREEN_HEIGHT / 2, Constants.CENTER_ANCHOR);
    text11.setBold(false);
  }
  
  private void drawMessage(Graphics g) {
    if (message != null) {
      DrawUtils.drawNotification(g, message, text8);
    }
  }
  
  private void drawTimeOut(Graphics g) {
    if (count > -1 && !isViewUser) {
      int drawIndex = 0;
      if (matchState == WAIT_TO_OPEN_CARD_STATE) {
        drawIndex = 0;
      } else {
        if (currentTurn != null) {
          drawIndex = getUserIndex(currentTurn);
        }
      }
      g.drawImage(chuyenLuotImg, countTimeOutLocation[drawIndex][0], countTimeOutLocation[drawIndex][1], GameConstants.CENTER_ANCHOR);
      text8.drawString2(g, String.valueOf(count / 10), GameColor.WHITE_CODE, countTimeOutLocation[drawIndex][0], countTimeOutLocation[drawIndex][1], GameConstants.CENTER_ANCHOR);
    }
  }
  
  private int getUserIndex(XiToPlayerInfo player) {
    if (player == null) {
      return 0;
    }
    for (int i = 0; i < players.size(); i++) {
      XiToPlayerInfo tmp = (XiToPlayerInfo) players.elementAt(i);
      if (player.getUser().getName().equals(tmp.getUser().getName())) {
        return i;
      }
    }
    return 0;
  }
  
  private void drawSelectCallBoard(Graphics g) {
    g.drawImage(bgButtonImage, Constants.SCREEN_WIDTH / 2, BUTTON_BG_Y, Constants.TOP_HCENTER_ANCHOR);
    g.drawImage(sliderImage, Constants.SCREEN_WIDTH / 2, BUTTON_BG_Y + SCROLL_DY, Constants.CENTER_ANCHOR);
    g.drawImage(backButtonImage, Constants.SCREEN_WIDTH / 2 - 70, BUTTON_BG_Y + SCROLL_DY, Constants.VCENTER_RIGHT_ANCHOR);
    g.drawImage(nextButtonImage, Constants.SCREEN_WIDTH / 2 + 70, BUTTON_BG_Y + SCROLL_DY, Constants.VCENTER_LEFT_ANCHOR);
    
    int sliderButtonX = (Constants.SCREEN_WIDTH - sliderImage.getWidth()) / 2 + 10 + (int) ((sliderImage.getWidth() - 20.0) * callMoneySelectedIndex / 4); 
    g.drawImage(sliderButtonImage, sliderButtonX, BUTTON_BG_Y + SCROLL_DY, Constants.CENTER_ANCHOR);
    
    GameImage callButton = followButtonImage;
    if (callMoneySelectedIndex != 0) {
      callButton = toButtonImage;
    }
    int totalButtonWidth = callButton.getWidth() + BUTTON_HOZ_DIS + cancelButtonImage.getWidth();
    int buttonX = (Constants.SCREEN_WIDTH - totalButtonWidth) / 2;
    g.drawImage(callButton, buttonX, BUTTON_BG_Y + BUTTON_DY, Constants.TOP_LEFT_ANCHOR);
    g.drawImage(cancelButtonImage, buttonX + callButton.getWidth() + BUTTON_HOZ_DIS, BUTTON_BG_Y + BUTTON_DY, Constants.TOP_LEFT_ANCHOR);
    
    // Draw select border
    g.setColor(GameColor.WHITE_CODE);
    switch (callMenuSelectedIndex) {
    case 0:
      g.drawRect(Constants.SCREEN_WIDTH / 2 - 90, BUTTON_BG_Y + SCROLL_DY - 10, 180, 20);
      break;
    case 1:
      g.drawRect(buttonX - 2, BUTTON_BG_Y + BUTTON_DY - 2, callButton.getWidth() + 4, callButton.getHeight() + 4);
      break;
    case 2:
      g.drawRect(buttonX + callButton.getWidth() + BUTTON_HOZ_DIS - 2, BUTTON_BG_Y + BUTTON_DY - 2, cancelButtonImage.getWidth() + 4, cancelButtonImage.getHeight() + 4);
      break;
    }
    
    // Draw money
    text11.drawString2(g, getGoldToCall() + " gold", GameColor.YELLOW_CODE, Constants.SCREEN_WIDTH / 2, BUTTON_BG_Y + BUTTON_DY - 18, Constants.TOP_HCENTER_ANCHOR);
  }
  
  private int getGoldToCall() {
    int moneyToCall = Global.currentTable.getBid();
    switch (callMoneySelectedIndex) {
    case 0: // Theo
      moneyToCall = followActionMoney;
      break;
    case 1: // Tố 1/4
      moneyToCall = lastCalledMoney + (int) (Global.currentTable.getBid() * 0.25);
      break;
    case 2: // Tố 1/2
      moneyToCall = lastCalledMoney + (int) (Global.currentTable.getBid() * 0.5);
      break;
    case 3: // Tố 
      moneyToCall = lastCalledMoney + Global.currentTable.getBid();
      break;
    case 4: // Tố gấp đôi
      moneyToCall = lastCalledMoney + Global.currentTable.getBid() * 2;
      break;
    }
    return moneyToCall;
  }
  
  private void drawGroupCardvalue(Graphics g, XiToPlayerInfo player, int x1, int y1, boolean isRightToLeft) {
    if (player.getUser().isViewUser()) {
      return;
    }
    
    if (hasCardValue) {
      int anchor1 = isRightToLeft ? GameConstants.TOP_RIGHT_ANCHOR : GameConstants.TOP_LEFT_ANCHOR;
      String groupCardValue = xiToGroupCardValue.getGroupCardType(player.getCardValue().getGroupType()) + getCardNameFromValue(player.getCardValue().getGroupMaxValue());
      
      g.setColor(GameColor.BLACK_CODE);
      int stringWidth = text8.stringWidth(groupCardValue);
      if (isRightToLeft) {
        g.fillRect(x1 - 4 - stringWidth, y1 + 2, stringWidth + 4, 18);
      } else {
        g.fillRect(x1 - 2, y1 + 2, stringWidth + 4, 18);
      }
      text8.drawString2(g, groupCardValue, GameColor.WHITE_CODE, x1, y1, anchor1);
    }
  }
  
  private void drawUserInfo(Graphics g, XiToPlayerInfo player, int x1, int y1, boolean isRightToLeft) {
    int anchor1 = isRightToLeft ? GameConstants.TOP_RIGHT_ANCHOR : GameConstants.TOP_LEFT_ANCHOR;
    if (players.size() < 5) {
      g.drawImage(Global.getAvatar(player.getUser().getName()), x1, y1, anchor1);
    }
    
    text8.setBold(true);
    if (player.getUser().getName().equals(Global.currentUser.getName())) {
      if (Constants.IS_240x320_SCREEN) {
        text8.drawString2(g, player.getUser().getName(), GameColor.WHITE_CODE, 110, Constants.SCREEN_HEIGHT - 100, Constants.TOP_HCENTER_ANCHOR);
        text8.drawString2(g, Global.currentUser.getGold() + " gold", GameColor.YELLOW_CODE, 110, Constants.SCREEN_HEIGHT - 85, Constants.TOP_HCENTER_ANCHOR);
      } else {
        text8.drawString2(g, player.getUser().getName(), GameColor.WHITE_CODE, 90, Constants.SCREEN_HEIGHT - 110, Constants.TOP_HCENTER_ANCHOR);
        text8.drawString2(g, Global.currentUser.getGold() + " gold", GameColor.YELLOW_CODE, 90, Constants.SCREEN_HEIGHT - 95, Constants.TOP_HCENTER_ANCHOR);
      }
    } else {
      text8.drawString2(g, player.getUser().getName(), GameColor.WHITE_CODE, x1, y1 + 35, anchor1);
    }
    text8.setBold(false);
  }
  
  private String getCardNameFromValue(int value) {
    return CARD_NAME[value % 13] + CARD_TYPE[value / 13];
  }
  
  private void drawUserCard(Graphics g, XiToPlayerInfo player, int x1, int y1, boolean isRotate, boolean isRightToLeft) {
    if (player == currentPlayer) {
      for (int i = 0; i < player.getClosedCards().size(); i++) {
        int card = ((Integer) player.getClosedCards().elementAt(i)).intValue();
        if (isRightToLeft) {
          drawCardImage(g, card, x1 - CARD_DISTANCE * i, y1 + 15, GameConstants.TOP_RIGHT_ANCHOR, isRotate);
        } else {
          drawCardImage(g, card, x1 + CARD_DISTANCE * i, y1 + 15, GameConstants.TOP_LEFT_ANCHOR, isRotate);
        }
        
        if ((i == currentChooseCard) && (matchState == WAIT_TO_OPEN_CARD_STATE) && player.getOpenedCards().size() < turnNumber) {
          g.drawImage(arrowImage, x1 + CARD_DISTANCE * i + 5, y1 - 2, GameConstants.TOP_HCENTER_ANCHOR);
        }
      }
    } else {
      for (int i = 0; i < player.getClosedCards().size(); i++) {
        if (isRotate) {
          if (isRightToLeft) {
            g.drawImage(rotatedImgBaiUp, x1, y1 + CARD_DISTANCE * (player.getClosedCards().size() - i), GameConstants.TOP_RIGHT_ANCHOR);
          } else {
            g.drawImage(rotatedImgBaiUp, x1, y1 + CARD_DISTANCE * i, GameConstants.TOP_LEFT_ANCHOR);
          }
        } else {
          if (isRightToLeft) {
            g.drawImage(imgBaiUp, x1 - CARD_DISTANCE * i, y1, GameConstants.TOP_RIGHT_ANCHOR);
          } else {
            g.drawImage(imgBaiUp, x1 + CARD_DISTANCE * i, y1, GameConstants.TOP_LEFT_ANCHOR);
          }
        }
      }
    }
    
    for (int i = 0; i < player.getOpenedCards().size(); i++) {
      int card = ((Integer) player.getOpenedCards().elementAt(i)).intValue();
      if (isRotate) {
        if (isRightToLeft) {
          drawCardImage(g, card, x1, y1 + CARD_DISTANCE * (player.getOpenedCards().size() - i + player.getClosedCards().size()), GameConstants.TOP_RIGHT_ANCHOR, isRotate);
        } else {
          drawCardImage(g, card, x1, y1 + CARD_DISTANCE * (player.getClosedCards().size() + i), GameConstants.TOP_LEFT_ANCHOR, isRotate);
        }
      } else {
        if (isRightToLeft) {
          drawCardImage(g, card, x1 - CARD_DISTANCE * (player.getClosedCards().size() + i), y1, GameConstants.TOP_RIGHT_ANCHOR, isRotate);
        } else {
          drawCardImage(g, card, x1 + CARD_DISTANCE * (player.getClosedCards().size() + i), y1, GameConstants.TOP_LEFT_ANCHOR, isRotate);
        }
      }
    }
  }
  
  private void drawCardImage(Graphics g, int quanBai, int x1, int y1, int anchor1, boolean isRotate) {
    if (!isRotate) {
      g.drawImage(getCard(quanBai), x1, y1, anchor1);
    } else {
      GameImage card = (GameImage) rotatedImageCache.get(new Integer(quanBai));
      if (card == null) {
        card = getCard(quanBai);
        card = ImageUtil.rotate(card, 90);
        rotatedImageCache.put(new Integer(quanBai), card);
      }
      g.drawImage(card, x1, y1, anchor1);
    }
  }
  
  private GameImage getCard(int quanBai) {
    if (cardImges[quanBai] == null) {
for1: for (int i = 0; i < 4; i++) {
        for (int j = 5; j < 13; j++) {
          int index = i * 13 + j;
          if (quanBai != index) {
            continue;
          }
          cardImges[index] = ImageUtil.getImage(Constants.CARD_IMAGE_CATEGORY, ((j == 12) ? 1 : (j + 2)) + "_" + cardOrder[i] + ".png");
          break for1;
        }
      }
    }
    return cardImges[quanBai];
  }
  
  private User getUserByName(String username) {
    for (int i = 0; i < Global.tableUsers.size(); i++) {
      User user = (User) Global.tableUsers.elementAt(i);
      if (user.getName().equals(username)) {
        return user;
      }
    }
    return null;
  }
  
  private XiToPlayerInfo getPlayerByName(String username) {
    for (int i = 0; i < players.size(); i++) {
      XiToPlayerInfo player = (XiToPlayerInfo) players.elementAt(i);
      if (player.getUser().getName().equals(username)) {
        return player;
      }
    }
    return null;
  }
  
  private void reorderListByUser() {
    // Find the index of current user
    int index = 0;
    for (int i = 0; i < players.size(); i++) {
      XiToPlayerInfo player = (XiToPlayerInfo) players.elementAt(i);
      if (player == currentPlayer) {
        index = i;
        break;
      }
    }
    
    while(index > 0) {
      Object obj = players.elementAt(0);
      players.removeElementAt(0);
      players.addElement(obj);
      index--;
    }
  }
  
  private void onUserViewJoin(DataPackage dataPackage) {
    String userJoin = dataPackage.nextString();
    User user = getUserByName(userJoin);
    if (user == null) {
      user = new User(userJoin);
      user.setViewUser(true);
      Global.tableUsers.addElement(user);
    }
    XiToPlayerInfo player = new XiToPlayerInfo(user);
    players.addElement(player);
    
    if (userJoin.equals(Global.currentUser.getName())) {
      currentPlayer = player;
    }
    
    prepareDrawLocation(players.size());
    reorderListByUser();
  }
  
  private void initForViewUser(DataPackage dataPackage) {
    isViewUser = true;
    
    MapDataPackage mapDataPackage = MapDataPackage.getMapPackage(dataPackage);
    for (int i = 0; i < players.size(); i++) {
      XiToPlayerInfo playerInfo = (XiToPlayerInfo) players.elementAt(i);
      String cardValue = mapDataPackage.getString(playerInfo.getUser().getName());
      getCardFromString(cardValue, playerInfo.getOpenedCards());
      Vector closedCards = playerInfo.getClosedCards();
      if (closedCards.isEmpty()) {
        closedCards.addElement(new Integer(1));
      }
    }
    
    // Init for chat
    // TODO: disable chat of game Xito
//    SocketClientUtil.joinChatRoom(USER_INFO_LOCATION_240x320[players.size() - 2], USER_INFO_LOCATION_320x240[players.size() - 2]);
  }
  
  public void getCardFromString(String data, Vector storage) {
    storage.removeAllElements();
    StringArray cards = GameStringUtils.split(data, ":");
    for (int i = 0; i < cards.len(); i++) {
      storage.addElement(Integer.valueOf(cards.get(i)));
    }
  }

  public void onRecieveData(DataPackage dataPackage) {
    int header = dataPackage.getHeader();
    switch (header) {
    case INIT_FOR_VIEW_USER_HEADER:
      initForViewUser(dataPackage);
      break;
    case USER_VIEW_JOIN_HEADER:
      onUserViewJoin(dataPackage);
      break;
    case TIME_OUT_RESPONSE:
      timeOutTime = dataPackage.nextInt() * 10;
      break;
    case INIT_TABLE_ERROR_RESPONSE:
      break;
    case USER_ORDER_RESPONSE:
      processUserOrder(dataPackage);
      break;
    case USER_LEFT_TABLE_RESPONSE:
      processUserLeftTable(dataPackage);
      break;
    case CARD_DELIVER_RESPONSE:
      processCardeliver(dataPackage);
      break;
    case USER_ACTION_NOTIFY_RESPONSE:
      int action = dataPackage.nextInt();
      switch (action) {
      case OPEN_CARD_REQUEST:
        processOpenCard(dataPackage);
        break;
      }
      break;
    case OPEN_CARD_RESULT_RESPONSE:
      processOpenCardResult(dataPackage);
      break;
    case FIRST_CALL_ALREADY_DONE:
      isTheFirstPlayerCall = false;
      callMoneySelectedIndex = 0;
      break;
    case START_CALL_ROUND_RESPONSE:
    case NEXT_TURN_RESPONSE:
      processStartCallRound(dataPackage);
      break;
    case UPDATE_GAME_INFO_RESPONSE:
      processUpdateGameInfo(dataPackage);
      break;
    case NOT_ENOUGH_MONEY_REPONSE:
      message = "Không đủ tiền";
      break;
    case SEND_RESULT_RESPONSE:
      processResult(dataPackage);
      break;
    }
  }
  
  private void processUserLeftTable(DataPackage dataPackage) {
    String leftUserName = dataPackage.nextString();
    XiToPlayerInfo player = getPlayerByName(leftUserName);
    if (player != null) {
      player.setLeftTable(true);
    }
  }
  
  private void processResult(DataPackage dataPackage) {
    int size = dataPackage.nextInt();
    resultName = StringArray.create(size);
    resultMoney = new int[size];
    for (int i = 0; i < size; i++) {
      if (dataPackage.hasMoreData()) {
        resultName.array[i] = dataPackage.nextString();
      }
      if (dataPackage.hasMoreData()) {
        resultMoney[i] = dataPackage.nextInt();
      }
    }
  }
  
  private void processStartCallRound(DataPackage dataPackage) {
    String username = dataPackage.nextString();
    followActionMoney = dataPackage.nextInt();
    currentTurn = getPlayerByName(username);
    count = timeOutTime;
  }
  
  private void processUserOrder(DataPackage dataPackage) {
    int numberOfPlayer = dataPackage.nextInt();
    players = new Vector();
    for (int i = 0; i < numberOfPlayer; i++) {
      String username = dataPackage.nextString();
      User user = getUserByName(username);
      XiToPlayerInfo player = new XiToPlayerInfo(user);
      players.addElement(player);
      
      if (username.equals(Global.currentUser.getName())) {
        currentPlayer = player;
      }
    }
    
    prepareDrawLocation(numberOfPlayer);
    reorderListByUser();
  }
  
  private void prepareDrawLocation(int numberOfPlayer) {
    if (GameConstants.IS_240x320_SCREEN) {
      userCardLocation = USER_CARDS_LOCATION_240x320[numberOfPlayer - 2];
      userInfoLocation = USER_INFO_LOCATION_240x320[numberOfPlayer - 2];
      cardValueLocation = CARD_VALUE_LOCATION_240x320[numberOfPlayer - 2];
      countTimeOutLocation = COUNT_TIME_OUT_LOCATION_240x320[numberOfPlayer - 2];
      addMoneyLocation = ADD_MONEY_LOCATION_240x320[numberOfPlayer - 2];
      isCardRightToLeft = IS_CARD_RIGHT_TO_LEFT_240x320[numberOfPlayer - 2];
      isRotateCard = IS_ROTATE_CARD_240x320[numberOfPlayer - 2];
      isInfoRightToLeft = IS_INFO_RIGHT_TO_LEFT_240x320[numberOfPlayer - 2];
    } else {
      userCardLocation = USER_CARDS_LOCATION_320x240[numberOfPlayer - 2];
      userInfoLocation = USER_INFO_LOCATION_320x240[numberOfPlayer - 2];
      cardValueLocation = CARD_VALUE_LOCATION_320x240[numberOfPlayer - 2];
      countTimeOutLocation = COUNT_TIME_OUT_LOCATION_320x240[numberOfPlayer - 2];
      addMoneyLocation = ADD_MONEY_LOCATION_320x240[numberOfPlayer - 2];
      isCardRightToLeft = IS_CARD_RIGHT_TO_LEFT_320x240[numberOfPlayer - 2];
      isRotateCard = IS_ROTATE_CARD_320x240[numberOfPlayer - 2];
      isInfoRightToLeft = IS_INFO_RIGHT_TO_LEFT_320x240[numberOfPlayer - 2];
    }
    // TODO: disable chat of game Xito
//    Global.initChatComponent(CHAT_LOCATION_240x320[numberOfPlayer - 2], CHAT_LOCATION_320x240[numberOfPlayer - 2]);
  }
  
  private void processCardeliver(DataPackage dataPackage) {
    int numberOfCard = dataPackage.nextInt();
    for (int i = 0; i < numberOfCard; i++) {
      int card = dataPackage.nextInt();
      currentPlayer.getClosedCards().addElement(new Integer(card));
    }
    
    // Thêm quân bài úp vào cho các đối thủ
    for (int i = 0; i < players.size(); i++) {
      XiToPlayerInfo player = (XiToPlayerInfo) players.elementAt(i);
      if (player != currentPlayer) {
        for (int j = 0; j < numberOfCard; j++) {
          player.getClosedCards().addElement(new Integer(1));
        }
      }
    }
  }
  
  private void processUpdateGameInfo(DataPackage dataPackage) {
    Global.systemCanvas.hideAlert();
    int newMatchState = dataPackage.nextInt();
    if (newMatchState != matchState) {
      matchState = newMatchState;
      if (newMatchState != END_MATCH_STATE) {
        count = timeOutTime;
      } else {
        count = -1;
        DrawUtils.getBottomBar(_manager).setCenterLabel("Chơi tiếp");
      }
    }
    allBid = dataPackage.nextInt();
    turnNumber = dataPackage.nextInt();
    Global.currentTable.setBid(dataPackage.nextInt());
    lastCalledMoney = dataPackage.nextInt();
  }
  
  private void processOpenCardResult(DataPackage dataPackage) {
    int playerSize = dataPackage.nextInt();
    for (int i = 0; i < playerSize; i++) {
      String playerName = dataPackage.nextString();
      int groupType = dataPackage.nextInt();
      int groupMaxValue = dataPackage.nextInt();
      
      XiToPlayerInfo player = getPlayerByName(playerName);
      player.getCardValue().setGroupType(groupType);
      player.getCardValue().setGroupMaxValue(groupMaxValue);
    }
    hasCardValue = true;
    drawCardValueCountTime = 30;
    message = null;
  }
  
  private void processOpenCard(DataPackage dataPackage) {
    String username = dataPackage.nextString();
    int card = dataPackage.nextInt();
    XiToPlayerInfo player = getPlayerByName(username);
    
    if (player == currentPlayer) {
      removeCard(card, player.getClosedCards());
      currentChooseCard = player.getClosedCards().size() - 1;
      player.getOpenedCards().addElement(new Integer(card));
    } else {
      player.getClosedCards().removeElementAt(0);
      player.getOpenedCards().addElement(new Integer(card));
    }
  }
  
  private void removeCard(int card, Vector cards) {
    for (int i = 0; i < cards.size(); i++) {
      Integer tmpCard = (Integer) cards.elementAt(i);
      if (tmpCard.intValue() == card) {
        cards.removeElementAt(i);
        break;
      }
    }
  }
  
  public void keyReleased(int keyCode) {
    if (!Key.isCommandKey) {
      if (Global.chatComponent != null) {
        Global.chatComponent.setShowInputChatMessageTextField(true);
        Global.chatComponent.keyReleased(keyCode);
      }
      return;
    }
    
    message = null;
    if (currentPlayer == null) {
      return;
    }
    switch (keyCode) {
    case Key.UP:
      if (isViewUser) {
        return;
      }
      
      if ((matchState == WAIT_TO_CALL_STATE) && (currentTurn == currentPlayer)) {
        callMenuSelectedIndex = --callMenuSelectedIndex < 0 ? 0 : callMenuSelectedIndex;
      }
      break;
    case Key.DOWN:
      if (isViewUser) {
        return;
      }
      
      if ((matchState == WAIT_TO_CALL_STATE) && (currentTurn == currentPlayer)) {
        callMenuSelectedIndex = ++callMenuSelectedIndex > 2 ? 2 : callMenuSelectedIndex;
      }
      break;
    case Key.LEFT:
      if (isViewUser) {
        return;
      }
      
      if ((matchState == WAIT_TO_OPEN_CARD_STATE) && currentPlayer.getOpenedCards().size() < turnNumber) {
        currentChooseCard = (--currentChooseCard < 0) ? 0 : currentChooseCard;
      } else {
        if ((matchState == WAIT_TO_CALL_STATE) && (currentTurn == currentPlayer)) {
          if (callMenuSelectedIndex == 0) {
            callMoneySelectedIndex = --callMoneySelectedIndex > 0 ? callMoneySelectedIndex : 0;
            // Nếu là người gọi đầu tiên thì không được phép theo
            if (isTheFirstPlayerCall && callMoneySelectedIndex == 0) {
              callMoneySelectedIndex = 1;
            }
          } else {
            callMenuSelectedIndex = 1;
          }
        }
      }
      break;
    case Key.RIGHT:
      if (isViewUser) {
        return;
      }
      
      if ((matchState == WAIT_TO_OPEN_CARD_STATE) && currentPlayer.getOpenedCards().size() < turnNumber) {
        currentChooseCard = (++currentChooseCard > currentPlayer.getClosedCards().size() - 1) ? currentPlayer.getClosedCards().size() - 1 : currentChooseCard;
      } else {
        if ((matchState == WAIT_TO_CALL_STATE) && (currentTurn == currentPlayer)) {
          if (callMenuSelectedIndex == 0) {
            callMoneySelectedIndex = ++callMoneySelectedIndex < 5 ? callMoneySelectedIndex : 4;
          } else {
            callMenuSelectedIndex = 2;
          }
        }
      }
      break;
    case Key.FIRE:
      if (Global.isShowedInputChatBox()) {
        SocketClientUtil.sendMessage(Global.chatComponent.getCurrentRoomId(), Global.chatComponent.getChatTextField().getText());
        Global.hideInputChatBox();
        return;
      }
      
      if ((matchState == WAIT_TO_OPEN_CARD_STATE) && currentPlayer.getOpenedCards().size() < turnNumber) {
        if (isViewUser) {
          return;
        }
        DataPackage dataPackage = Game.createGamePackage(OPEN_CARD_REQUEST);
        dataPackage.putInt(((Integer) currentPlayer.getClosedCards().elementAt(currentChooseCard)).intValue());
        Global.gameActionClient.write(dataPackage);
        count = -1;
      } else if (matchState == END_MATCH_STATE) {
        GameGlobal.nextState(FrmGroupTableFreeUserFriend.instance(), null);
      } else if ((matchState == WAIT_TO_CALL_STATE) && (currentTurn == currentPlayer)) {
        if (isViewUser) {
          return;
        }
        int callType = -1;
        if ((callMenuSelectedIndex == 0) || (callMenuSelectedIndex == 1)) {
          switch (callMoneySelectedIndex) {
          case 0: // Theo
            callType = FOLLOW_CALL_ACTION_TYPE;
            break;
          case 1: // Tố 1/4
            callType = QUART_CALL_ACTION_TYPE;
            break;
          case 2: // Tố 1/2
            callType = HAFT_CALL_ACTION_TYPE;
            break;
          case 3: // Tố 
            callType = FULL_CALL_ACTION_TYPE;
            break;
          case 4: // Tố gấp đôi
            callType = DOUBLE_CALL_ACTION_TYPE;
            break;
          }
        } else {
          callType = RETREAT_CALL_ACTION_TYPE;
        }
        
        if (callType > -1) {
          DataPackage dataPackage = Game.createGamePackage(CALL_ACTION_REQUEST);
          dataPackage.putInt(callType);
          Global.gameActionClient.write(dataPackage);
          Global.alert.showAlert(this, GameAlert.LOADING_WITH_NO_BUTTON_TYPE, "Đang tố...").setAlertTimeOut(10000);
        }
      }
      break;
    case Key.SOFT_RIGHT:
      if (isViewUser) {
        SocketClientUtil.leaveTableRequest();
        GameGlobal.nextState(FrmGroupListTableFreeUserChat.instance(), null);
      } else {
        if (matchState != END_MATCH_STATE) {
          if (Global.isShowedInputChatBox()) {
            Global.chatComponent.getChatTextField().deleteLastChar();
          } else {
            Global.alert.showAlert1(this, GameAlert.YES_NO_TYPE, StringArray.create1("Thoát ra ra sẽ bị phạt tiền", "Bạn có muốn thoát"), 99);
          }
        } else {
          GameGlobal.nextState(FrmGroupTableFreeUserFriend.instance(), null);
        }
      }
      break;
    }
  }
  
  public void alertEventPerform(int alertType, int eventType, int alertId) {
    if (alertId == 99 && eventType == GameAlert.YES_BUTTON) {
      SocketClientUtil.leaveTableRequest();
      GameGlobal.nextState(FrmGroupListTableFreeUserChat.instance(), null);
    }
  }
  
  public void onConnectDone() {
  }

  public void onConnectFail() {
  }

  public void onDisconnect() {
  }
  
  public void doTask() {
    if (count > -1) {
      count--;
    }
    
    if (drawCardValueCountTime > 0) {
      drawCardValueCountTime--;
    }
  }
  
  public void destroy() {
    cardOrder = null;
    rotatedImageCache = null;
    backButtonImage = null;
    nextButtonImage = null;
    sliderButtonImage = null;
    bgButtonImage = null;
    followButtonImage = null;
    toButtonImage = null;
    cancelButtonImage = null;
    sliderImage = null;
    
    userCardLocation = null;
    userInfoLocation = null;
    cardValueLocation = null;
    countTimeOutLocation = null;
    isCardRightToLeft = null;
    isInfoRightToLeft = null;
    players = null;
    currentPlayer = null;
    
    imgBaiUp = null;
    rotatedImgBaiUp = null;
    cardImges = null;
    chuyenLuotImg = null;
    tableImage = null;
    arrowImage = null;
    
    text8 = null;
    text11 = null;
    
    currentTurn = null;
    resultName = null;
    resultMoney = null;
    message = null;
  }
}
